#include "TestCube.h"
#include <RCGame.h>

TestCube::TestCube(void)
{
	Color = XMFLOAT4(1,1,1,1);

	D3D11_INPUT_ELEMENT_DESC l[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    };

	memcpy(layout,l,sizeof(D3D11_INPUT_ELEMENT_DESC) * ARRAYSIZE(l));

	PositionTexVertex v[] = 
    {
        { XMFLOAT3( -0.5f, 0.5f, -0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
        { XMFLOAT3( 0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
        { XMFLOAT3( 0.5f, 0.5f, 0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
        { XMFLOAT3( -0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },

        { XMFLOAT3( -0.5f, -0.5f, -0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
        { XMFLOAT3( 0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
        { XMFLOAT3( 0.5f, -0.5f, 0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
        { XMFLOAT3( -0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },

        { XMFLOAT3( -0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
        { XMFLOAT3( -0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
        { XMFLOAT3( -0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
        { XMFLOAT3( -0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },

        { XMFLOAT3( 0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
        { XMFLOAT3( 0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
        { XMFLOAT3( 0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
        { XMFLOAT3( 0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },

        { XMFLOAT3( -0.5f, -0.5f, -0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
        { XMFLOAT3( 0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
        { XMFLOAT3( 0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
        { XMFLOAT3( -0.5f, 0.5f, -0.5f ), XMFLOAT2( 0.0f, 1.0f ) },

        { XMFLOAT3( -0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
        { XMFLOAT3( 0.5f, -0.5f, 0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
        { XMFLOAT3( 0.5f, 0.5f, 0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
        { XMFLOAT3( -0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
    };

	memcpy(vertices,v,sizeof(PositionTexVertex) * ARRAYSIZE(v));

	WORD i[] =
    {
        3,1,0,
        2,1,3,

        6,4,5,
        7,4,6,

        11,9,8,
        10,9,11,

        14,12,13,
        15,12,14,

        19,17,16,
        18,17,19,

        22,20,21,
        23,20,22		
    };

	memcpy(indices,i,sizeof(WORD) * ARRAYSIZE(i));
}

TestCube::~TestCube(void){ }

void TestCube::Initialize()
{
	ID3D11Device* device = pGame->getGraphicsDevice()->getDevice();
	// Compile the vertex shader
    ID3DBlob* pVSBlob = NULL;
    HRESULT hr = RCGame::CompileShaderFromFile( L"Tutorial07.fx", "VS", "vs_4_0", &pVSBlob );
    if( FAILED( hr ) )
    {
        MessageBox( NULL,
                    L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
        return;
    }

	// Create the vertex shader
	hr = device->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &pVertexShader );
    if( FAILED( hr ) )
    {    
        pVSBlob->Release();
        return;
    }

	UINT numElements = ARRAYSIZE( layout );

    // Create the input layout
    hr = device->CreateInputLayout( layout, numElements, pVSBlob->GetBufferPointer(),
                                          pVSBlob->GetBufferSize(), &pVertexLayout );
    pVSBlob->Release();

	// Compile the pixel shader
    ID3DBlob* pPSBlob = NULL;
    hr = RCGame::CompileShaderFromFile( L"Tutorial07.fx", "PS", "ps_4_0", &pPSBlob );
    if( FAILED( hr ) )
    {
        MessageBox( NULL,
                    L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
        return;
    }

    // Create the pixel shader
    hr = device->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &pPixelShader );
    pPSBlob->Release();
    if( FAILED( hr ) )
        return;

	// Create vertex buffer
	D3D11_BUFFER_DESC bd;
    ZeroMemory( &bd, sizeof(bd) );
    bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = sizeof( PositionTexVertex ) * 24;
    bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    bd.CPUAccessFlags = 0;
    D3D11_SUBRESOURCE_DATA InitData;
    ZeroMemory( &InitData, sizeof(InitData) );
    InitData.pSysMem = vertices;
    hr = device->CreateBuffer( &bd, &InitData, &pVertexBuffer );
    if( FAILED( hr ) )
        return;
	
	// Build index
	bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = sizeof( WORD ) * 36;
    bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
    bd.CPUAccessFlags = 0;
    InitData.pSysMem = indices;
    hr = device->CreateBuffer( &bd, &InitData, &pIndexBuffer );
    if( FAILED( hr ) )
        return;

	// Create the constant buffers
	bd.Usage = D3D11_USAGE_DEFAULT;
    bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    bd.ByteWidth = sizeof(CBChangeOnResize);
    hr = device->CreateBuffer( &bd, NULL, &pCBChangeOnResize );
    if( FAILED( hr ) )
        return;
    
    bd.ByteWidth = sizeof(CBChangesEveryFrame);
    hr = device->CreateBuffer( &bd, NULL, &pCBChangesEveryFrame );
    if( FAILED( hr ) )
        return;

    // Load the Texture
    hr = D3DX11CreateShaderResourceViewFromFile( device, L"seafloor.dds", NULL, NULL, &pTextureRV, NULL );
    if( FAILED( hr ) )
        return;

	// Create the sample state
    D3D11_SAMPLER_DESC sampDesc;
    ZeroMemory( &sampDesc, sizeof(sampDesc) );
    sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
    sampDesc.MinLOD = 0;
    sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
    hr = device->CreateSamplerState( &sampDesc, &pSamplerLinear );
    if( FAILED( hr ) )
        return;
}

void TestCube::Draw(float time)
{
	ID3D11DeviceContext* context = pGame->getGraphicsDevice()->getDeviceContext();

	// Set the input layout
    context->IASetInputLayout( pVertexLayout );

	// Set vertex buffer
    UINT stride = sizeof( PositionTexVertex );
    UINT offset = 0;
    context->IASetVertexBuffers( 0, 1, &pVertexBuffer, &stride, &offset );

	// Set index buffer
    context->IASetIndexBuffer( pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 );

    // Set primitive topology
    context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );


	// Initialize the projection matrix    
    CBChangeOnResize cbChangesOnResize;
	cbChangesOnResize.mProjection = XMMatrixTranspose( camera->getProjection() );
    context->UpdateSubresource( pCBChangeOnResize, 0, NULL, &cbChangesOnResize, 0, 0 );

	//
    // Update variables that change once per frame
    //
    CBChangesEveryFrame cb;
	cb.mWorld = XMMatrixTranspose( getWorld() );
    cb.vMeshColor = Color;
	cb.mView = XMMatrixTranspose( camera->getView()  );
    context->UpdateSubresource( pCBChangesEveryFrame, 0, NULL, &cb, 0, 0 );

	// Render the cube
	context->VSSetShader( pVertexShader, NULL, 0 );
    context->VSSetConstantBuffers( 0, 1, &pCBChangeOnResize );
    context->VSSetConstantBuffers( 1, 1, &pCBChangesEveryFrame );
    context->PSSetShader( pPixelShader, NULL, 0 );
    context->PSSetConstantBuffers( 1, 1, &pCBChangesEveryFrame );
    context->PSSetShaderResources( 0, 1, &pTextureRV );
    context->PSSetSamplers( 0, 1, &pSamplerLinear );
    context->DrawIndexed( 36, 0, 0 );   

	ID3D11ShaderResourceView* texres = NULL;
	context->PSSetShaderResources(0, 1, &texres); // immediately unbind the texture
}

void TestCube::setCamera(IRCCamera* cam)
{
	camera = cam;
}



bool TestCube::getVisible()
{
	return Visible;
}
void TestCube::setVisible(bool value)
{
	Visible = value;
}